package com.shan.tools.starter.datasource;

import com.alibaba.druid.pool.DruidDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.sql.SQLException;
import java.util.Collections;
import java.util.stream.Collectors;

/**
 * 数据库连接池工具类
 **/
@Slf4j
public class DBHelper {
    private final static String DEFAULT_URL_PREFIX = "jdbc:mysql://%s/%s?";

    private final static String REPLICATE_URL_PREFIX = "jdbc:mysql:replication://%s/%s?";

    private final static String URL_SUFFIX = "autoReconnect=true&useCompression=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true";

    private final static String DEFAULT_DRIVER = "com.mysql.jdbc.Driver";

    private final static String REPLICATE_DRIVER = "com.mysql.jdbc.ReplicationDriver";

    private final static String HOST_SEPARATOR = ",";

    public static DruidDataSource buildDataSource(DataSourceProperties dbProperties) {

        validate(dbProperties);

        DruidDataSource dataSource = new DruidDataSource();

        if (CollectionUtils.isEmpty(dbProperties.getSlaveUrls())) {
            String host = String.format(DEFAULT_URL_PREFIX, dbProperties.getMasterUrl(), dbProperties.getName());
            dataSource.setDriverClassName(DEFAULT_DRIVER);
            dataSource.setUrl(host + URL_SUFFIX);
        } else {
            dbProperties.getSlaveUrls().add(0, dbProperties.getMasterUrl());
            String host = String.format(REPLICATE_URL_PREFIX, dbProperties.getSlaveUrls().stream().collect(Collectors.joining(HOST_SEPARATOR)), dbProperties.getName());
            dataSource.setDriverClassName(REPLICATE_DRIVER);
            dataSource.setUrl(host + URL_SUFFIX);
        }
        dataSource.setUsername(dbProperties.getUsername());
        dataSource.setPassword(dbProperties.getPassword());

        log.info("load datasource properties success：host={}", dataSource.getUrl());

        // 以下为druid的优化参数
        dataSource.setMinIdle(dbProperties.getMinIdle());
        dataSource.setMaxActive(dbProperties.getMaxActive());
        dataSource.setMaxWait(dbProperties.getMaxWait());
        dataSource.setInitialSize(dbProperties.getInitialSize());
        dataSource.setPoolPreparedStatements(dbProperties.isPoolPreparedStatements());
        dataSource.setMaxOpenPreparedStatements(dbProperties.getMaxOpenPreparedStatements());
        dataSource.setValidationQuery(dbProperties.getValidationQuery());
        dataSource.setValidationQueryTimeout(dbProperties.getValidationQueryTimeout());
        dataSource.setTestOnBorrow(dbProperties.isTestOnBorrow());
        dataSource.setTestOnReturn(dbProperties.isTestOnReturn());
        dataSource.setTestWhileIdle(dbProperties.isTestWhileIdle());
        dataSource.setMinEvictableIdleTimeMillis(dbProperties.getMinEvictableIdleTimeMillis());
        dataSource.setRemoveAbandonedTimeout(dbProperties.getRemoveAbandonedTimeout());
        dataSource.setConnectionInitSqls(dbProperties.getConnectionInitSqls());

        try {
            dataSource.setFilters(dbProperties.getFilters());
            dataSource.setUseGlobalDataSourceStat(dbProperties.isUseGlobalDataSourceStat());
            dataSource.init();
        } catch (SQLException e) {
            log.error("load datasource error, dbProperties is :{}", e);
        }

        return dataSource;
    }

    private static void validate(DataSourceProperties dbProperties) {
        if (dbProperties == null) {
            throw new RuntimeException("datasource config is null");
        }

        if (StringUtils.isEmpty(dbProperties.getName())) {
            throw new RuntimeException("datasource name is null");
        }

        if (StringUtils.isEmpty(dbProperties.getMasterUrl())) {
            throw new RuntimeException("datasource master url is null");
        }

        if (StringUtils.isEmpty(dbProperties.getUsername())) {
            throw new RuntimeException("datasource username url is null");
        }

        if (StringUtils.isEmpty(dbProperties.getPassword())) {
            throw new RuntimeException("datasource password url is null");
        }
    }
}
